#ifndef FEATURETERM_CLASS
#define FEATURETERM_CLASS


/* NOOS tokens: */ 
#define TOKEN_LEFT_PAR		0
#define TOKEN_RIGHT_PAR		1
#define TOKEN_SYMBOL		2
#define TOKEN_INTEGER		3
#define TOKEN_STRING		4
#define TOKEN_FLOAT			5
#define TOKEN_ROOT			6
#define TOKEN_PARENT		7
#define TOKEN_INIT_VARIABLE	8
#define TOKEN_REF_VARIABLE	9
#define TOKEN_SINGLETON		10

typedef List<Symbol> Path;


/* Used to support the ">>" and "." symbols of the NOOS syntax:	*/ 
/* assign f.feature = root.p							*/ 
class NOOSPathRecord {
public:
	NOOSPathRecord() {
		f=0;
		feature=0;
		root=0;
		p=0;
	} 
	~NOOSPathRecord() {
		f=0;
		root=0;
		if (feature!=0) delete feature;
		feature=0;
		if (p!=0) delete p;
		p=0;
	}

	FeatureTerm *f;
	Symbol *feature;
	FeatureTerm *root;
	Path *p;
};

/* Used to support the "?x" and "!x" symbols of the enhanced NOOS syntax: */ 
class NOOSVariableRecord {
public:
	NOOSVariableRecord() {
		f=0;
		variable=0;
	} 
	~NOOSVariableRecord() {
		f=0;
		if (variable!=0) delete variable;
		variable=0;
	}
	Symbol *variable;
	FeatureTerm *f;
};

class NOOSVariableLinkRecord {
public:
	NOOSVariableLinkRecord() {
		f=0;
		variable=0;
		feature=0;
	} 
	~NOOSVariableLinkRecord() {
		f=0;
		if (variable!=0) delete variable;
		variable=0;
		if (feature!=0) delete feature;
		feature=0;
	}
	FeatureTerm *f;
	Symbol *feature;
	Symbol *variable;
};



/*

	String format:

	sort
	( ivalue |
	  fvalue |
	  svalue |
	  n [ ('name' name|'noname') (nfeatures (featurename feature)* | nelements (setelement)*) ]
	)

*/


class FeatureTerm {
	friend class FeatureTermContainer;
	friend class FTKBase;

public:

	FeatureTerm(void);			/* Defines an empty ft without name */ 

	FeatureTerm(Symbol *name,int i,Ontology *o);
	FeatureTerm(Symbol *name,float f,Ontology *o);
	FeatureTerm(Symbol *name,Symbol *s,Ontology *o); /* Creates a symbol value */ 
	FeatureTerm(Symbol *name,Sort *sort,int nfeatures,...);
	FeatureTerm(Symbol *name,class SpecialTerm *st,Sort *sort);

	FeatureTerm(char *name,int i,Ontology *o);
	FeatureTerm(char *name,float f,Ontology *o);
	FeatureTerm(char *name,char *s,Ontology *o);
	FeatureTerm(char *name,Sort *sort,int nfeatures,...);
	FeatureTerm(char *name,SpecialTerm *st,char *sort,Ontology *o);

	FeatureTerm(FeatureTerm &f);
	FeatureTerm(FeatureTerm *f);
	FeatureTerm(FeatureTermContainer *fv);

	~FeatureTerm();

	static FeatureTerm *SetFeatureTerm(void);
	static FeatureTerm *SetFeatureTerm(Symbol *name);
	static FeatureTerm *SetFeatureTerm(char *name);

	void assign(FeatureTerm *f);
	
	FeatureTerm *clone(void);	/* Makes an independent copy of the Feature Term */ 
	FeatureTerm *clone(class FTKBase *dm);	/* Makes an independent copy of the Feature Term, but does  */ 
											/* not duplicate those elements of the domain model			*/ 

	// These functions work as the previuos ones, but they return the correspondence between old nodes ans new nodes:
	FeatureTerm *clone(List<FeatureTerm> *old_nodes,List<FeatureTerm> *new_nodes);	
	FeatureTerm *clone(class FTKBase *dm,List<FeatureTerm> *old_nodes,List<FeatureTerm> *new_nodes);	

	/* These functions work as the prvious ones, but they clone a list of terms, and if they have common terms */ 
	/* among them, the relations are kept. */ 
	static List<FeatureTerm> *clone(List<FeatureTerm> *l);
	static List<FeatureTerm> *clone(List<FeatureTerm> *l,FTKBase *dm);

	FeatureTerm *cloneUnnamed(class FTKBase *dm);	/* The clone has no names  */ 												

	FeatureTerm *featureValue(Symbol *feature);	/* its return value has to be freed */ 
	FeatureTerm *featureValueQuick(Symbol *feature); /* its return value has not to be freed, but does not work with sets */ 
	void defineFeatureValue(Symbol *feature,FeatureTerm *value);
	bool defineFeatureValueSecure(Symbol *feature,FeatureTerm *value); /* checks the SORT to see if the feature exists */ 
	FeatureTerm *featureValue(char *feature);
	FeatureTerm *featureValueQuick(char *feature); /* its return value has not to be freed, but does not work with sets */ 
	void defineFeatureValue(char *feature,FeatureTerm *value);
	bool defineFeatureValueSecure(char *feature,FeatureTerm *value); /* checks the SORT to see if the feature exists */ 
	List<FeatureTerm> *readPath(Path *path);

	void removeFeatureValue(char *feature);
	void removeFeatureValue(Symbol *feature);
	void removeSetValue(FeatureTerm *value);

	FeatureTerm *addSetValue(FeatureTerm *value);

	Sort *getSort(void);
	void setSort(Sort *); /* This only works for FT sorts, not for integer, float or symbol sorts */ 
	Symbol *getName(void);
	void setName(Symbol *);

	int getDataType(void);
	bool isAbstract(void);
	bool isInt(void);
	bool isFloat(void);
	bool isSymbol(void);
	bool isFeatureTerm(void);
	bool isSet(void);
	bool isSpecial(void);

	bool hasValue(void); /* This, returns true, if a feature term of type int,float or symbol has a concrete value */ 

	class FeatureTermContainer* get_content(void);

	int getInt(void);
	bool specificIntValueP(void);
	float getFloat(void);
	bool specificFloatValueP(void);
	Symbol *getSymbol(void);
	SpecialTerm *getSpecialTerm(void);
	List<FeatureTerm> *set_values(void); /* returns a list of all the valus contained in the set (that has to be destroyed) */ 
	List<FeatureTerm> *set_values_quick(void); /* returns a list of all the valus contained in the set (that does not have to be destroyed) */ 

	// NOOS Parsing routines:
	char *toStringNOOS(void);
	char *toStringNOOS(FTKBase *dm); /* Does not expand the objects present in the domain model but prints their name */ 
	static FeatureTerm *fromStringNOOS(char *s,FTKBase *m,Ontology *o);
	static FeatureTerm *fromFileNOOS(FILE *fp,FTKBase *m,Ontology *o);

	void get_paths(List<Path> *l);

	bool subsumes(FeatureTerm *f);

	bool operator==(FeatureTerm &f);
	bool equivalents(FeatureTerm *f);
	bool same(FeatureTerm *f); /* checks if they both point to the same FeatureTermContainer node */ 

	int  size(void);
	int  depth(void);
	void nodes(List<FeatureTerm> **nl); /* returns a list containing all the nodes of a feature term */ 
	void nodesPaths(List<FeatureTerm> **nl,List<Path> **pl); /* returns a list containing all the nodes of a feature term and their paths */ 
	void nodesPathsSorts(List<FeatureTerm> **nl,List<Path> **pl,List<Sort> **sl,Ontology *o); 
										/* returns a list containing all the nodes of a feature term and their paths, */ 
										/* plus the most general sort that a node can be (specified in the ontology). */ 
	void nodesAllPaths(List<FeatureTerm> **nl,List< List<Path> > **pl); /* returns a list containing all the nodes of a feature term and all the paths i which they appear */ 
	void nodesAllPathsSorts(List<FeatureTerm> **nl,List< List<Path> > **pl,List< List<Sort> > **sl,Ontology *o); 
										/* returns a list containing all the nodes of a feature term and all the	  */ 
									    /* paths in which they apear,												  */ 
										/* plus the most general sort that a node can be (specified in the ontology). */ 
	void nodesAllPathsSortsParents(List<FeatureTerm> **nl,List< List<Path> > **pl,List< List<Sort> > **sl,List< List<FeatureTerm> > **parentsl,Ontology *o); 
	void nodesAllPathsSortsParents(List<FeatureTerm> **nl,List< List<Path> > **pl,List< List<Sort> > **sl,List< List<FeatureTerm> > **parentsl,Ontology *o,FTKBase *domain_model); 
										/* returns a list containing all the nodes of a feature term and all the	  */ 
									    /* paths in which they apear,												  */ 
										/* plus the most general sort that a node can be (specified in the ontology). */ 
										/* And which is the parent node in the feature term.						  */ 

	void Allnodes(List<FeatureTerm> **nl,Ontology *o,FTKBase *domain_model); 
										/* Returns ALL the FeatureTerm objects that compose a Feature Term (not only  */ 
										/* all the FeatureTermContainers).											  */ 


	void set_paths(List<Path> *l);
	void set_paths_intersection(List<Path> *l);	// computes the set paths of an object, and computes the intersection of them
												// with the paths in "l", the return value is also in "l".
	FeatureTerm *clone_substituting(FeatureTerm *v1,FeatureTerm *v2);
	FeatureTerm *clone_substituting(FeatureTerm *v1,FeatureTerm *v2,FTKBase *dm);
	FeatureTerm *clone_linking(FeatureTerm *v1,FeatureTerm *v2,FTKBase *dm);
	FeatureTerm *clone_keepingTrackOfNode(FeatureTerm *node,FeatureTerm **newnode,FTKBase *dm);
	FeatureTerm *clone_keepingTrackOf2Nodes(FeatureTerm *node1,FeatureTerm **newnode1,FeatureTerm *node2,FeatureTerm **newnode2,FTKBase *dm);
	int substitute(FeatureTerm *v1,FeatureTerm *v2);

	bool hasSetsP(void);
	bool hasPathEqualtiesP(void);
	bool hasPathEqualtiesP(class FTKBase *dm); // does not consider equalties of domain objects as path equalties 

	bool leafP(void);	/* True if the object is an integer, float, symbol or a FT without features */ 

	int num_of_references(void);

protected:
	bool hasSetsP_internal(List<class FeatureTermContainer> *l);
	bool hasPathEqualtiesP_internal(List<class FeatureTermContainer> *l);
	bool hasPathEqualtiesP_internal(List<class FeatureTermContainer> *l,class FTKBase *dm);
	
	void Delete(void);

	FeatureTerm *cloneInternal(List<class FeatureTermContainer> *old_correspondences,List<FeatureTerm> *new_correspondences);
	FeatureTerm *cloneInternal(List<class FeatureTermContainer> *old_correspondences,List<FeatureTerm> *new_correspondences,class FTKBase *dm);
	FeatureTerm *cloneInternal2(List<FeatureTermContainer> *old_correspondences,List<FeatureTerm> *old_correspondences2,List<FeatureTerm> *new_correspondences,class FTKBase *dm);
		/* keeps track of exactly each FeatureTerm to which FeatureTerm has been mapped in the cloned object */ 

	FeatureTerm *cloneInternalUnnamed(List<class FeatureTermContainer> *old_correspondences,List<FeatureTerm> *new_correspondences);
	FeatureTerm *cloneInternalUnnamed(List<class FeatureTermContainer> *old_correspondences,List<FeatureTerm> *new_correspondences,class FTKBase *dm);

	void toStringNOOSInternal(List<char> *tokens,List<FeatureTermContainer> *bindings,int tabs,FTKBase *dm);

	// NOOS Importer internal functions:
	int fromStringNOOS_nonstatic(char *s,FTKBase *m,Ontology *o);
	FeatureTerm *fromStringNOOSInternal(char *s,FTKBase *m,Ontology *o,Sort *vsort,int *pos,List<FeatureTerm> *hierarchy,List<NOOSPathRecord> *nprl,List<NOOSVariableRecord> *nvl,List<NOOSVariableLinkRecord> *nvll,List<FeatureTerm> *specials);
	static FeatureTerm *fromFileNOOSInternal(FILE *fp,FTKBase *m,Ontology *o,Sort *vsort,List<FeatureTerm> *hierarchy,List<NOOSPathRecord> *nprl,List<NOOSVariableRecord> *nvl,List<NOOSVariableLinkRecord> *nvll,List<FeatureTerm> *specials);
	static char *getTokenNOOS(char *s,int *type,int *pos);
	static char *getTokenNOOS(FILE *fp,int *type);

	void get_paths_internal(Path *current_path,List<Path> *l);

	void delete_circular_structure(List<FeatureTermContainer> *l,List<FeatureTerm> *expanded,List<FeatureTerm> *delayed);

	class FeatureTermContainer *m_ft;
};



class FeatureTermContainer {

	friend class FeatureTerm;
	friend class FTKBase;

public:
	
	FeatureTermContainer(Symbol *name,int p_value,int p_type,Ontology *o);
	FeatureTermContainer(Symbol *name,float p_value,int p_type,Ontology *o);	
	FeatureTermContainer(Symbol *name,Symbol *s,Ontology *o);	
	FeatureTermContainer(Symbol *name,Sort *sort,int nfeatures,va_list features);
	FeatureTermContainer(char *name,Sort *sort,int nfeatures,va_list features);
	FeatureTermContainer(Symbol *name);
	FeatureTermContainer(Symbol *name,SpecialTerm *st,Sort *sort);	
	~FeatureTermContainer();


	bool AddSetValue(FeatureTerm *value);

private:
	/* auxiliar function for the "delete" operator: */ 
	void num_of_references(FeatureTerm *ft,List<FeatureTermContainer> *l1,List<List<FeatureTerm> > *l2);


	Symbol *m_name;
	int m_reference_count;
	int m_data_type;		 /* 0 : int, 1: float, 2: symbol, 3: feature_term, 4: set */ 
							 /* data_type is duplicated in order to increase efficiency by not having */ 
							 /* to access m_sort */ 
	Sort *m_sort;

	union {
		struct {
			int m_value;
			int m_type;		/* 0: value, -1: undefined	*/ 
		} m_i;
		struct {
			float m_value;
			int m_type;		/* 0: value, -1: undefined	*/ 
		} m_f;
		Symbol *m_s;
		struct {
			List<Symbol> *m_feature_name;
			List<FeatureTerm> *m_feature_value;						
		} m_ft;
//		class FeatureTermContainer *m_ft;
		List<FeatureTerm> *m_set;
		class SpecialTerm *m_special;
	} m_value;
};



#endif
